﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GameFramework.ModelManager;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using GameFramework.Audio;

namespace MyRaceGame.GameLogic
{
    public class RacerCharacter : SkinnedGameCharacter, IComparable, IAudioEmitter
    {
        public RacerCharacter()
        {
        }

        public RacerCharacter(RacerCharacter copy)
            : this(copy.unmanagedModel, copy.position, copy.rotation, copy.scale, copy.graphicsDevice,
            copy.name, copy.raceTrack, ((RacerAnimationPlayer)copy.AnimationPlayer).IdleAnimation,
            ((RacerAnimationPlayer)copy.AnimationPlayer).WalkAnimation,
            ((RacerAnimationPlayer)copy.AnimationPlayer).RunAnimation, copy.isHuman, copy.speed)
        {
        }

        public RacerCharacter(Model model, Vector3 position, Vector3 rotation,
            Vector3 scale, GraphicsDevice graphicsDevice, string name, RaceTrack raceTrack, string idleAnimation, 
            string walkAnimation, string runAnimation, bool isHuman = false, float speed = 0, float initialDistance = 0)
            : base(model, position, rotation, scale, graphicsDevice, name, isHuman)
        {
            this.raceTrack = raceTrack;
            this.speed = speed;
            initialRotation = rotation.Y;
            animationPlayer = new RacerAnimationPlayer(this, idleAnimation, walkAnimation, runAnimation);
            distance = initialDistance;
        }

        public override void Update(GameTime gameTime)
        {
            trackPosition = raceTrack.TracePath(distance, out direction);

            if (speed < 0)
                speed = 0;

            distance += speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            totalTrackLength += speed;

            float rot = initialRotation + (float)Math.Acos(direction.Y > 0 ? -direction.X : direction.X);

            if (direction.Y > 0)
                rot += MathHelper.Pi;
            rot += MathHelper.PiOver2;

            position = new Vector3(trackPosition.X, 0, trackPosition.Y);
            rotation = new Vector3(0, rot + MathHelper.Pi, 0);

            playSpeed = speed * modelSpeedFactor;

            //RaceGame.Instance.AudioManager.Play3DSound(@"Audio\run", true, this);

            base.Update(gameTime);
        }

        public override bool Equals(object obj)
        {
            RacerCharacter otherRacer = (RacerCharacter)obj;
            return name == otherRacer.Name;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public virtual int CompareTo(object obj)
        {
            RacerCharacter racer2 = (RacerCharacter)obj;
            if (this.totalTrackLength / this.raceTrack.TrackLength >
               racer2.TotalTrackLength / racer2.RaceTrack.TrackLength)
                return -1;
            //if (this.totalTrackLength == racer2.totalTrackLength)
            //    return 0;
            return 1;
        }

        public virtual RaceTrack RaceTrack
        {
            get { return raceTrack; }
            set { raceTrack = value; }
        }

        public virtual float TotalTrackLength
        {
            get { return totalTrackLength; }
            set { totalTrackLength = value; }
        }

        public virtual float InitialRotation
        {
            get { return initialRotation; }
            set { initialRotation = value; }
        }

        public virtual float Distance
        {
            get { return distance; }
            set { distance = value; }
        }

        public virtual float Speed
        {
            get { return speed; }
            set { speed = value; }
        }

        public virtual Vector3 Forward
        {
            get
            {
                Matrix rotationMatrix = Matrix.CreateRotationY(rotation.Y);
                return Vector3.Transform(Vector3.Forward, rotationMatrix);
            }
        }

        public virtual Vector3 Up
        {
            get { return Vector3.Up; }
        }

        public virtual Vector3 Velocity
        {
            get
            {
                return Forward * speed;
            }
        }

        protected float modelSpeedFactor = 0.0001f;
        protected RaceTrack raceTrack;
        protected float distance, speed;
        protected float initialRotation;
        protected float totalTrackLength = 0.0f;
        protected Vector2 trackPosition;
        protected Vector2 direction;
    }
}
